﻿using System;
using System.Diagnostics;
using System.Runtime.Caching;
using System.Web;
using DapperExtensions;

namespace AspNetSample
{
    public class DapprInterceptor : IDapperInterceptor
    {
        private const string TokenName = "Authorization";
        private const int Timeout = 1000; // 毫秒

        private static MemoryCache Cache => MemoryCache.Default;

        private static bool TryGetCacheKey(out string key)
        {
            if (HttpContext.Current == null)
            {
                key = null;
                return false;
            }

            key = HttpContext.Current.Request.Headers.Get(TokenName);
            if (key == null)
            {
                return false;
            }

            return true;
        }

        /// <summary>
        /// 记录写操作
        /// </summary>
        private void Write()
        {
            if (TryGetCacheKey(out var cacheKey))
            {
                return;
            }

            Cache.Set(cacheKey,
                new DbExecutionContext { RouteHints = "/* maxscale route to master */ " },
                DateTimeOffset.Now.AddMilliseconds(Timeout));
        }

        public void OnExecuting(DapperContext context)
        {
            if (TryGetCacheKey(out var cacheKey))
            {
                return;
            }

#if DEBUG
            Debug.WriteLine("Original SQL: " + context.CommandText);
#endif
            var ctx = Cache.Get(cacheKey) as DbExecutionContext;

            if (ctx != null)
            {
                if (!string.IsNullOrEmpty(ctx.RouteHints))
                {
#if DEBUG
                    Debug.WriteLine("Route hints: " + ctx.RouteHints);
#endif

                    // 加入路由
                    context.CommandText = ctx.RouteHints + context.CommandText;

#if DEBUG
                    Debug.WriteLine("Route SQL: " + context.CommandText);
#endif
                }
#if DEBUG
                else
                {
                    Debug.WriteLine("Route hints is empty");
                }
            }
#endif

            if (ContainsIgnoreCase(context.CommandText, "insert ")
                    || ContainsIgnoreCase(context.CommandText, "update ")
                    || ContainsIgnoreCase(context.CommandText, "delete ")
                    || ContainsIgnoreCase(context.CommandText, "replace ")
                   )
            {
                // 记录写操作
                if (ctx == null)
                {
                    ctx = new DbExecutionContext
                    {
                        RouteHints = "/* maxscale route to master */ "
                    };
                }
                else
                {
                    if (string.IsNullOrEmpty(ctx.RouteHints))
                    {
                        ctx.RouteHints = "/* maxscale route to master */ ";
                    }
                    else if (!ctx.RouteHints.StartsWith("/* maxscale route to", StringComparison.Ordinal)
                             && !ctx.RouteHints.StartsWith("-- maxscale route to", StringComparison.Ordinal)
                             && !ctx.RouteHints.StartsWith("# maxscale route to", StringComparison.Ordinal))
                    {
                        ctx.RouteHints = "/* maxscale route to master */ ";
                    }
                }

                Cache.Set(cacheKey, ctx, DateTimeOffset.Now.AddMilliseconds(Timeout));
            }
        }

        private static bool ContainsIgnoreCase(string source, string toCheck)
        {
            return source?.IndexOf(toCheck, StringComparison.OrdinalIgnoreCase) >= 0;
        }

        /// <summary>
        /// 记录数据库执行上下文
        /// </summary>
        class DbExecutionContext
        {
            /// <summary>
            /// 是否应该将下次查询路由到主库
            /// </summary>
            public string RouteHints { get; set; }
        }
    }
}